package com.kusen.text;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Mac;

import static com.kusen.text.StringTest.getRandomString;

/**
 * 获取喜马拉雅上的专辑下的详情数据
 */
public class SignatureDemo {
    private static final String DEFAULT_ENCODING = "UTF-8";
    private static final String HMAC_SHA1 = "HmacSHA1";

    public static void main(String[] args) {
        //https://api.ximalaya.com/open_pay/browse_paid_album_tracks?
        // app_key=b617866c20482d133d5de66fceb37da3
        // &client_os_type=4
        // &nonce=8c80cff7deb3c05569e663039216058e
        // &server_api_version=1.0.0
        // &album_id=11501536
        // &sort=asc
        // &page=1
        // &count=10
        // &contains_track_rich_intro=true
        // &sig=27e3358cac2544fe5b3f7ac5a36f3147
        Map<String, String> result = new LinkedHashMap<>();
        String app_key = XimalayaConfig.app_key;
        String nonce = getRandomString(32);
        String timestamp = String.valueOf(new Date().getTime());
        result.put("app_key", app_key);
        result.put("client_os_type", "4");
        result.put("nonce", nonce);
        result.put("server_api_version", "1.0.0");
        result.put("album_id", "24818634");
        result.put("sort", "asc");
        result.put("page", "1");
        result.put("count", "10");
        result.put("contains_track_rich_intro", "true");
        //result.put("timestamp",timestamp);
        String keyHash = XimalayaConfig.app_secret + XimalayaConfig.serverAuthenticateStaticKey;
        try {
            String sig = caculateSignature(result, keyHash);
            result.put("sig", sig);
            StringBuffer sb = new StringBuffer(XimalayaConfig.url).append(XimalayaConfig.albumUrl).append("?");
            String completeUrl = getCompleteUrl(sb, result);
            System.out.println(completeUrl + "\n");
            String s = doGet(completeUrl);

        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private static String getCompleteUrl(StringBuffer sb, Map<String, String> result) {
        for (Map.Entry<String, String> entry : result.entrySet()) {
            sb.append(entry.getKey());
            sb.append("=");
            sb.append(entry.getValue());
            sb.append("&");
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }

    /**
     * 计算参数的签名值 demo
     *
     * @param paramsMap
     * @param seed:     seed即为app_secret+serverAuthenticateStaticKey
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException
     */
    public static String caculateSignature(Map<String, String> paramsMap, String seed) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
        if (paramsMap == null || paramsMap.isEmpty() || seed == null) {
            throw new IllegalArgumentException("paramsMap and seed should not empty");
        }

        if (!(paramsMap instanceof TreeMap<?, ?>)) {
            paramsMap = new TreeMap<String, String>(paramsMap);
        }
        StringBuilder paramsBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
            paramsBuilder.append(entry.getKey());
            paramsBuilder.append("=");
            paramsBuilder.append(entry.getValue());
            paramsBuilder.append("&");
        }
        paramsBuilder.deleteCharAt(paramsBuilder.length() - 1);
        String paramsEncodedStr = base64Encode(paramsBuilder.toString());
        String sig = hmacSHA1ToStr(paramsEncodedStr, seed);
//		LOG.debug(String.format("caculateSignature, paramsMap: %s, paramsEncodedStr: %s, seed: %s, caculated sig: %s", paramsMap, paramsEncodedStr,
//				seed, sig));
        return sig;
    }

    /**
     * HMAC SHA1签名或摘要算法
     *
     * @param data
     * @param key
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     */
    private static String hmacSHA1ToStr(String data, String key) throws InvalidKeyException, NoSuchAlgorithmException {
        if (data == null || key == null) {
            return null;
        }
        return hmacSHA1ToStr(data.getBytes(), key.getBytes());
    }

    /**
     * HMAC SHA1签名或摘要算法
     *
     * @param data 待摘要的字节数据
     * @param key  使用的key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    private static String hmacSHA1ToStr(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
        return DigestUtils.md5Hex(hmacSHA1(data, key));
    }

    private static byte[] hmacSHA1(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
        if (data == null || key == null) {
            return null;
        }

        SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1);
        Mac mac = Mac.getInstance(HMAC_SHA1);
        mac.init(signingKey);
        return mac.doFinal(data);
    }

    /**
     * Base64编码
     *
     * @param data 字符串数据
     * @return
     * @throws UnsupportedEncodingException
     */
    private static String base64Encode(String data) throws UnsupportedEncodingException {
        if (data == null) {
            return null;
        }
        return Base64.encodeBase64String(data.getBytes(DEFAULT_ENCODING));
    }


    public static String doPost(String r) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        HttpURLConnection conn = null;
        try {
            URL url = new URL(r);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            //发送POST请求必须设置为true
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(10000);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            //获取输出流
            out = new OutputStreamWriter(conn.getOutputStream());
            String jsonStr = "{\"qry_by\":\"name\", \"name\":\"Tim\"}";
            out.write(jsonStr);
            out.flush();
            out.close();
            //取得输入流，并使用Reader读取
            if (200 == conn.getResponseCode()) {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                    System.out.println(line);
                }
            } else {
                System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        return result.toString();
    }

    public static String doGet(String URL) {
        HttpURLConnection conn = null;
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder result = new StringBuilder();
        try {
            //创建远程url连接对象
            URL url = new URL(URL);
            //通过远程url连接对象打开一个连接，强转成HTTPURLConnection类
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(60000);
            conn.setRequestProperty("Accept", "application/json");
            //conn.setRequestProperty("connection", "Keep-Alive");
            //conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            //发送请求
            conn.connect();
            //通过conn取得输入流，并使用Reader读取
            if (200 == conn.getResponseCode()) {
                is = conn.getInputStream();
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                String line;
                while ((line = br.readLine()) != null) {
                    result.append(line);
                    System.out.println(line);
                }
            } else {
                System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
            conn.disconnect();
        }
        return result.toString();
    }


    /**
     * 向指定URL发送GET方法的请求
     *
     * @param url 发送请求的URL
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGet(String url) {
        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url;
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet()) {
                System.out.println(key + "--->" + map.get(key));
            }
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常！" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }


}
